namespace ScrumSprintMonitor.UI.Wpf.Behaviors
{
	#region #using Directives

	using System;
	using System.Diagnostics;
	using System.Windows;
	using System.Windows.Controls;
	using System.Windows.Data;
	using System.Windows.Media;
	using System.Windows.Media.Animation;
	using System.Windows.Shapes;

	using Progress;

	#endregion

	public static class BusyIndicatorBehavior
	{
		#region Attached Properties

		public static readonly DependencyProperty BusyStateProperty = DependencyProperty.RegisterAttached("BusyState", typeof(bool),
		                                                                                                  typeof(BusyIndicatorBehavior),
		                                                                                                  new UIPropertyMetadata(false, OnBusyStateChanged));

		public static readonly DependencyProperty DimBackgroundProperty = DependencyProperty.RegisterAttached("DimBackground", typeof(bool),
		                                                                                                      typeof(BusyIndicatorBehavior),
		                                                                                                      new UIPropertyMetadata(true));

		public static readonly DependencyProperty DimmerBrushProperty = DependencyProperty.RegisterAttached("DimmerBrush", typeof(Brush),
		                                                                                                    typeof(BusyIndicatorBehavior),
		                                                                                                    new UIPropertyMetadata(Brushes.Black));

		public static readonly DependencyProperty DimTransitionDurationProperty = DependencyProperty.RegisterAttached("DimTransitionDuration",
		                                                                                                              typeof(Duration),
		                                                                                                              typeof(BusyIndicatorBehavior),
		                                                                                                              new UIPropertyMetadata(
		                                                                                                              	new Duration(TimeSpan.FromSeconds(1.0))));


		public static readonly DependencyProperty TargetVisualProperty = DependencyProperty.RegisterAttached("TargetVisual", typeof(UIElement),
		                                                                                                     typeof(BusyIndicatorBehavior),
		                                                                                                     new UIPropertyMetadata(null));

		public static Duration GetDimTransitionDuration(DependencyObject obj)
		{
			return (Duration) obj.GetValue(DimTransitionDurationProperty);
		}

		public static void SetDimTransitionDuration(DependencyObject obj, Duration value)
		{
			obj.SetValue(DimTransitionDurationProperty, value);
		}

		public static Brush GetDimmerBrush(DependencyObject obj)
		{
			return (Brush) obj.GetValue(DimmerBrushProperty);
		}

		public static void SetDimmerBrush(DependencyObject obj, Brush value)
		{
			obj.SetValue(DimmerBrushProperty, value);
		}

		public static bool GetDimBackground(DependencyObject obj)
		{
			return (bool) obj.GetValue(DimBackgroundProperty);
		}

		public static void SetDimBackground(DependencyObject obj, bool value)
		{
			obj.SetValue(DimBackgroundProperty, value);
		}

		public static UIElement GetTargetVisual(DependencyObject obj)
		{
			return (UIElement) obj.GetValue(TargetVisualProperty);
		}

		public static void SetTargetVisual(DependencyObject obj, UIElement value)
		{
			obj.SetValue(TargetVisualProperty, value);
		}

		public static bool GetBusyState(DependencyObject obj)
		{
			return (bool) obj.GetValue(BusyStateProperty);
		}

		public static void SetBusyState(DependencyObject obj, bool value)
		{
			obj.SetValue(BusyStateProperty, value);
		}

		#endregion

		#region Implementation

		private static void OnBusyStateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			bool isBusy = (bool) e.NewValue;
			bool wasBusy = (bool) e.OldValue;

			if (isBusy == wasBusy)
			{
				return;
			}

			var hostGrid = (Grid) (GetTargetVisual(d) ?? d);
			Debug.Assert(hostGrid != null);
			if (isBusy)
			{
				Debug.Assert(LogicalTreeHelper.FindLogicalNode(hostGrid, "BusyIndicator") == null);

				var grid = new Grid
				           	{
				           		Name = "BusyIndicator",
				           		Opacity = 0.0
				           	};
				grid.SetBinding(FrameworkElement.WidthProperty, new Binding("ActualWidth")
				                                                	{
				                                                		Source = hostGrid
				                                                	});
				grid.SetBinding(FrameworkElement.HeightProperty, new Binding("ActualHeight")
				                                                 	{
				                                                 		Source = hostGrid
				                                                 	});
				for (int i = 1; i <= 3; ++i)
				{
					grid.ColumnDefinitions.Add(new ColumnDefinition
					                           	{
					                           		Width = new GridLength(1, GridUnitType.Star)
					                           	});
					grid.RowDefinitions.Add(new RowDefinition
					                        	{
					                        		Height = new GridLength(1, GridUnitType.Star)
					                        	});
				}

				var viewbox = new Viewbox
				              	{
				              		HorizontalAlignment = HorizontalAlignment.Center,
				              		Stretch = Stretch.Uniform,
				              		StretchDirection = StretchDirection.Both,
				              		Child = new CircularProgressBar()
				              	};
				grid.SetValue(Panel.ZIndexProperty, 1000);
				grid.SetValue(Grid.RowSpanProperty, Math.Max(1, hostGrid.RowDefinitions.Count));
				grid.SetValue(Grid.ColumnSpanProperty, Math.Max(1, hostGrid.ColumnDefinitions.Count));
				viewbox.SetValue(Grid.RowProperty, 1);
				viewbox.SetValue(Grid.ColumnProperty, 1);
				viewbox.SetValue(Panel.ZIndexProperty, 1);
				if (GetDimBackground(d))
				{
					var dimmer = new Rectangle
					             	{
					             		Opacity = 0.5,
					             		Fill = GetDimmerBrush(d)
					             	};
					dimmer.SetValue(Grid.RowSpanProperty, 3);
					dimmer.SetValue(Grid.ColumnSpanProperty, 3);
					dimmer.SetValue(Panel.ZIndexProperty, 0);
					grid.Children.Add(dimmer);
				}
				grid.Children.Add(viewbox);

				grid.BeginAnimation(UIElement.OpacityProperty, new DoubleAnimation(1.0, GetDimTransitionDuration(d)));

				hostGrid.Children.Add(grid);
			}
			else
			{
				var grid = (Grid) LogicalTreeHelper.FindLogicalNode(hostGrid, "BusyIndicator");

				Debug.Assert(grid != null);

				if (grid != null)
				{
					var fadeOutAnimation = new DoubleAnimation(0.0, GetDimTransitionDuration(d));
					fadeOutAnimation.Completed += (sender, args) => OnFadeOutAnimationCompleted(hostGrid, grid);
					grid.BeginAnimation(UIElement.OpacityProperty, fadeOutAnimation);
				}
			}
		}

		private static void OnFadeOutAnimationCompleted(Panel hostGrid, UIElement busyIndicator)
		{
			hostGrid.Children.Remove(busyIndicator);
		}

		#endregion
	}
}